//! util相关模块
//!
use serde::{Deserialize, Serialize};
use std::time::SystemTime;

/// 单位的基本数据
#[derive(Serialize, Deserialize)]
struct UnitBasic {
    /// 是否为移动单位
    move_flag: bool,
    /// 每毫秒移动的距离
    speed: usize,
    /// 视力范围
    sight_range: usize,
}

/// 状态更新
#[derive(Serialize, Deserialize, Copy, Clone)]
pub enum UnitState {
    /// 定义方向 (移动方向，开始移动的时间)
    Move(MoveDir),
    /// 暂停状态
    Stop,
}

impl Default for UnitState {
    fn default() -> Self {
        UnitState::Stop
    }
}

/// 移动方向
#[derive(Eq, PartialEq, Serialize, Deserialize, Copy, Clone)]
pub enum MoveDir {
    Left,
    LeftTop,
    LeftDown,
    Right,
    RightTop,
    RightDown,
    Top,
    Down,
}

/// 地图基础数据
#[derive(Deserialize, Serialize)]
struct MapBasic {
    /// 长 一共有多少个格子
    width: usize,
    /// 宽 一共有多少个格子
    height: usize,
    /// 格子的长
    grid_width: usize,
    /// 格子的宽
    grid_height: usize,
}

/// 单位随时间变化的数据会存放到这里
#[derive(Serialize, Deserialize)]
struct UnitTrasientent {
    /// 所在的格子
    grid_coordinate: (usize, usize),
    /// 所在坐标
    coordinate: (usize, usize),
    /// 所在地图的基础数据 单位是可能切换地图的
    map_basic: MapBasic,
}

struct UnitViolate {
    /// 状态 不会进行存储，任何加载回来的单位状态都应该是呆在原地
    state: UnitState,
    /// 上次更新状态的时间
    last_modify_state_time: SystemTime,
}

impl Default for UnitViolate {
    fn default() -> Self {
        UnitViolate {
            last_modify_state_time: SystemTime::now(),
            ..Default::default()
        }
    }
}

#[derive(Serialize, Deserialize, Copy, Clone)]
pub enum UnitType {
    Sheep,
}

/// 简易信息
/// 当单位状态改变时，会生成改信息传递给附近单位
pub struct SimpleUnitChangeStateMsg {
    pub ty: UnitType,
    pub old_state: UnitState,
    pub new_state: UnitState,
    pub old_coordinate: (usize, usize),
    pub new_coordinate: (usize, usize),
    pub grid_coordinate: (usize, usize),
}
//// 简易信息
/// 当单位进入新格子时，会生成改信息传递给附近单位
pub struct SimpleUnitEnterGridMsg {
    pub ty: UnitType,
    pub coordinate: (usize, usize),
    pub grid_coordinate: (usize, usize),
}
/// 简易信息
/// 当单位状态改变时，会生成改信息传递给附近单位
pub struct SimpleUnitLeaveGridMsg {
    pub ty: UnitType,
    pub coordinate: (usize, usize),
    pub grid_coordinate: (usize, usize),
}
/// 格子单位
///
/// TODO 同步位置 将自己的位置同步到对应的管理协程
/// 如玩家位置就通知给玩家，npc就通知给npc的管理线程
/// 这种应该交给kv来进行
#[derive(Serialize, Deserialize)]
pub struct Unit {
    /// 单位id
    id: usize,
    /// 单位类型
    ty: UnitType,
    /// 单位的基础数据，不会发生变化 是所有单位都会拥有的数据，且不会因为外界发生改变
    unit_basic: UnitBasic,
    /// 单位过渡数据，会发生变化 需要进行保存
    unit_trasientent: UnitTrasientent,
    /// 单位易失数据 不用考虑保存
    #[serde(skip)]
    unit_violate: UnitViolate,
}

impl Unit {
    /// 获取id
    #[inline]
    pub fn get_id(&self) -> usize {
        self.id
    }

    /// 获取所在地图的格子长
    #[inline]
    pub fn get_grid_width(&self) -> usize {
        self.unit_trasientent.map_basic.grid_width
    }

    /// 获取所在地图的格子的宽
    #[inline]
    pub fn get_grid_height(&self) -> usize {
        self.unit_trasientent.map_basic.grid_height
    }

    /// 获取单位状态
    #[inline]
    pub fn get_state(&self) -> UnitState {
        self.unit_violate.state
    }

    /// 设置状态
    #[inline]
    pub fn set_state(&mut self, new_state: UnitState) {
        self.unit_violate.state = new_state;
    }

    /// 获取视野范围
    #[inline]
    pub fn get_sight_range(&self) -> usize {
        self.unit_basic.sight_range
    }

    /// 设置上次状态修改时间
    #[inline]
    pub fn set_last_modify_state_time(&mut self, time: SystemTime) {
        self.unit_violate.last_modify_state_time = time;
    }

    /// 获取类型
    #[inline]
    pub fn get_type(&self) -> UnitType {
        self.ty
    }

    /// 获得所在的格子
    #[inline]
    pub fn get_grid_coordinate(&self) -> (usize, usize) {
        self.unit_trasientent.grid_coordinate
    }

    /// 设置所在的格子
    #[inline]
    pub fn set_grid_corrdinate(&mut self, grid_coordinate: (usize, usize)) {
        self.unit_trasientent.grid_coordinate = grid_coordinate;
    }

    /// 获取所在的坐标
    #[inline]
    pub fn get_coordinate(&self) -> (usize, usize) {
        self.unit_trasientent.coordinate
    }

    /// 设置所在的坐标
    #[inline]
    pub fn set_coordinate(&mut self, coordinate: (usize, usize)) {
        self.unit_trasientent.coordinate = coordinate;
    }

    /// 是否在视野范围内
    fn is_in_view(&self, grid_coordinate: (usize, usize), coordinate: (usize, usize)) -> bool {
        let distance_pow = self.distance_pow(grid_coordinate, coordinate);
        self.get_sight_range() * self.get_sight_range() >= distance_pow
    }

    // /// 更新坐标并进行同步
    // /// 计算目前到达的位置，理论上不应该出格子
    // fn update_and_sync_pos(&mut self) -> Result<()> {
    //     fn move_top_or_left(old: usize, elapsed: u128, speed: usize) -> Result<usize> {
    //         let move_distance = elapsed as usize * speed;
    //         if move_distance > old {
    //             return Err(anyhow!("定位服务同步位置错误 err_code: 01"));
    //         }
    //         Ok(old - move_distance)
    //     }

    //     fn move_down_or_right(old: usize, elapse: u128, speed: usize) -> Result<usize> {
    //         let new = old + (elapse as usize) * speed;
    //         if new > GRID_LENGTH {
    //             return Err(anyhow!("定位服务同步位置错误 err_code: 02"));
    //         }
    //         Ok(new)
    //     }

    //     let (old_x, old_y) = self.unit_trasientent.coordinate;
    //     let (new_x, new_y) = match &self.state {
    //         UnitState::Move(dir, start_time) => {
    //             // 计算过了多久，毫秒级别
    //             let elapsed = start_time
    //                 .elapsed()
    //                 .context(format!("定位服务同步位置时，计算时间错误"))?
    //                 .as_millis();
    //             // 计算新坐标
    //             match dir {
    //                 MoveDir::Down => {
    //                     let new_y = move_down_or_right(old_y, elapsed, self.get_speed())?;
    //                     (old_x, new_y)
    //                 }
    //                 MoveDir::Top => {
    //                     let new_y = move_top_or_left(old_y, elapsed, self.get_speed())?;
    //                     (old_x, new_y)
    //                 }
    //                 MoveDir::Left => {
    //                     let new_x = move_top_or_left(old_x, elapsed, self.get_speed())?;
    //                     (new_x, old_y)
    //                 }
    //                 MoveDir::Right => {
    //                     let new_x = move_down_or_right(old_x, elapsed, self.get_speed())?;
    //                     (new_x, old_y)
    //                 }
    //                 MoveDir::LeftTop => {
    //                     let new_x = move_top_or_left(old_x, elapsed, self.get_speed())?;
    //                     let new_y = move_top_or_left(old_y, elapsed, self.get_speed())?;
    //                     (new_x, new_y)
    //                 }
    //                 MoveDir::LeftDown => {
    //                     let new_x = move_top_or_left(old_x, elapsed, self.get_speed())?;
    //                     let new_y = move_down_or_right(old_y, elapsed, self.get_speed())?;
    //                     (new_x, new_y)
    //                 }
    //                 MoveDir::RightTop => {
    //                     let new_x = move_down_or_right(old_x, elapsed, self.get_speed())?;
    //                     let new_y = move_top_or_left(old_y, elapsed, self.get_speed())?;
    //                     (new_x, new_y)
    //                 }
    //                 MoveDir::RightDown => {
    //                     let new_x = move_down_or_right(old_x, elapsed, self.get_speed())?;
    //                     let new_y = move_down_or_right(old_y, elapsed, self.get_speed())?;
    //                     (new_x, new_y)
    //                 }
    //             }
    //         }
    //         _ => (0, 0),
    //     };
    //     self.unit_trasientent.coordinate = (new_x, new_y);
    //     // TODO 是否需要进行位置的同步 把位置同步给其他协程
    //     Ok(())
    // }

    /// 计算与另一个单位之间的距离的平方
    fn distance_pow(&self, grid_coordinate: (usize, usize), coordinate: (usize, usize)) -> usize {
        /// 单轴上的距离
        fn axis_distance(
            grid: usize,
            src: usize,
            other_grid: usize,
            other: usize,
            grid_length: usize,
        ) -> usize {
            if grid > other_grid {
                (grid - other_grid - 1) * grid_length + (grid_length - other) + src
            } else {
                (grid - other_grid - 1) * grid_length + (grid_length - src) + other
            }
        }

        let (grid_x, grid_y) = self.unit_trasientent.grid_coordinate;
        let (x, y) = self.unit_trasientent.coordinate;

        let (other_grid_x, other_grid_y) = grid_coordinate;
        let (other_x, other_y) = coordinate;
        // x轴上距离 由grid数组列和grid内的x计算
        let x_distance = axis_distance(grid_y, x, other_grid_y, other_x, self.get_grid_width());
        // y轴上距离 由grid数组行和grid内的y计算
        let y_distance = axis_distance(grid_x, y, other_grid_x, other_y, self.get_grid_height());

        x_distance * x_distance + y_distance * y_distance
    }

    /// 发现附近的单位进入新的格子
    pub fn find_nearby_unit_enter_grid(&self, nearby_unit: &SimpleUnitEnterGridMsg) {
        if !self.is_in_view(nearby_unit.grid_coordinate, nearby_unit.coordinate) {
            return;
        }
        match self.get_type() {
            _ => {}
        }
    }

    /// 发现附近的单位状态发生变化
    pub fn find_nearby_unit_state_change(&self, nearby_unit: &SimpleUnitChangeStateMsg) {
        if !self.is_in_view(nearby_unit.grid_coordinate, nearby_unit.new_coordinate) {
            return;
        }

        match self.get_type() {
            _ => {}
        }
    }

    /// 发现附近的单位离开了旧格子
    pub fn find_nearby_unit_leave_grid(&self, nearby_unit: &SimpleUnitLeaveGridMsg) {
        if !self.is_in_view(nearby_unit.grid_coordinate, nearby_unit.coordinate) {
            return;
        }
        match self.get_type() {
            _ => {}
        }
    }

    /// 验证新坐标是否合法
    /// TODO 目前做的是单机 还没做多人 这个是多人需要的
    pub fn validate_new_coordinate(&self, _new_pos: (usize, usize)) -> bool {
        true
    }

    /// 验证新的格子是否合法
    pub fn validate_new_grid_coordinate(&self, _new_grid_coordinate: (usize, usize)) -> bool {
        true
    }
}
